技巧94 扫描一个“坏”Docker镜像
Docker生态系统中大家很快认识到的问题之一就是其脆弱性——如果你的镜像不可改变,就无法获得任何安全修复。如果你遵循Docker最佳实践中的镜像极简主义准则,这可能也不是问题,但是这很难讲。
镜像扫描器就是作为这一问题的解决方案而创建的,但是它还是没解决如何评估它们的问题。
问题
想要知道镜像扫描器的效率如何。
解决方案
创建一个“已知的坏”镜像来测试扫描器。
我们在工作中要面对这种问题。有很多Docker镜像扫描器存在(如Clair),但是商业软件声称可以更加深入镜像来确定任何潜在的问题。
但是含有已知并且文档标明的漏洞以供我们测试这些扫描器的镜像并不存在。这不出奇,因为大多数镜像并不标榜自己不安全!
因此我们创建了一个已知的坏镜像。这一镜像可供下载:
$ docker pull imiell/bad-dockerfile
原则很简单:创建一个带有注明了的漏洞的镜像,然后在你候选的扫描器里指定该镜像。
该Dockerfile的最新版本还处于变化之中,所以这里没有印出。但是,它的形式还是相当简单的:
FROM <base image> ⇽--- 该引用的坏dockerfile仓库使用了一个centos镜像,但是你可以换成接近你自己的基础镜像的镜像
RUN <install 'bad' software> ⇽---
COPY <copy 'bad' software in> ⇽--- 一系列的RUN/COPY/ADD命令来向这个镜像安装有漏洞的软件
[...]
CMD echo 'Vulnerable image' && /bin/false ⇽--- 因为显而易见的原因,让这个镜像尽量不允许自己执行的CMD命令
这一镜像含有各种各样的漏洞,足以让扫描器尽其所能。
在最简单的情况下,该镜像使用包管理器下载了各种各样有漏洞的软件。在各个领域,该Docker镜像都试图包含各种严重性的漏洞。
更复杂的植入漏洞的方式是使用,例如,复制有漏洞的JavaScript代码,使用各语言特定的包管理器(如JavaScript的npm、Ruby的gem和Python的pip)来安装有漏洞的代码,甚至编译特定版本的bash(有臭名昭著的Shellshock漏洞的那一版),将其放置在一个意想不到的位置来避免使用很多扫描技巧。
讨论
你可能会觉得最好的扫描方案就是能抓到最多的CVE的那个。但是这可不一定。显然,扫描器能找到镜像中的漏洞是很好的。但是除此之外,扫描漏洞可能比起科学更像是一门艺术。
提示
公共漏洞与暴露(Common Vulnerability Exposure,CVE)是对于通用软件中的特定漏洞的一个标识符。一个CVE的例子可能是CVE-2001-0067,起始的4个字母代表发现的年份,第二部分代表了那一年发现的漏洞数。
例如,一个漏洞可能非常严重(如在你的宿主机上获得root权限),但是很难暴露出来(如需要一个国家的资源)。你(或者你负责的组织)可能更加担忧哪些没那么严重但是比较容易暴露的漏洞。例如,对你的系统有DoS攻击,这没有数据泄露或渗透的风险,但是可能因此无法开展业务,所以你可能更想给它打个补丁,而不是某些需要价值几万美金的计算力才能发起的模糊加密器攻击。
什么是DOS攻击
DoS代表“denial of service”(拒绝服务)。这意味着,这种攻击可以降低你的系统按照指令工作的能力。拒绝服务攻击可以压迫Web服务器以至于它无法为合法用户提供服务。
同时,对于运行中的容器,也值得考虑一下该漏洞是否真的存在。镜像里可能有一个老版本的Apache服务器,但是如果它从来没运行过,这个漏洞就可以忽略。这很常见。包管理器经常带来一些并不是真正需要的依赖,只不过是为了让依赖管理更简单点。
如果安全确实是一个大问题,那么这也是有小镜像的另一个理由(见第7章)——就算有软件没用到,它仍然可能在安全扫描里出现,浪费了组织需要来搞明白需不需要打补丁的时间。
本技巧希望能让你思考哪个扫描器才是最合适的。一如既往,这是一种花费、需求以及为了获取正确的解决方式而花费的力气之间的平衡。